/**
 * Copyright (c) 2011-2020, hubin (jobob@qq.com).
 * <p>
 * Licensed under the Apache License, Version 2.0 (the "License"); you may not
 * use this file except in compliance with the License. You may obtain a copy of
 * the License at
 * <p>
 * http://www.apache.org/licenses/LICENSE-2.0
 * <p>
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
 * License for the specific language governing permissions and limitations under
 * the License.
 */
package com.mrlv.db.druid;


import com.baomidou.mybatisplus.plugins.parser.ISqlParser;
import com.baomidou.mybatisplus.toolkit.PluginUtils;
import org.apache.ibatis.executor.statement.StatementHandler;
import org.apache.ibatis.mapping.BoundSql;
import org.apache.ibatis.mapping.MappedStatement;
import org.apache.ibatis.mapping.SqlCommandType;
import org.apache.ibatis.plugin.*;
import org.apache.ibatis.reflection.MetaObject;
import org.apache.ibatis.reflection.SystemMetaObject;
import org.apache.ibatis.scripting.defaults.DefaultParameterHandler;
import org.apache.ibatis.session.RowBounds;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.util.Arrays;
import java.util.Map;
import java.util.Properties;

import static java.util.stream.Collectors.joining;

/**
 * <p>
 * 重写分页拦截器
 * </p>
 */
/*
@Setter
@Accessors(chain = true)
*/
//@Intercepts({@Signature(type = StatementHandler.class, method = "prepare", args = {Connection.class, Integer.class})})
//public class TenantPaginationInterceptor extends AbstractSqlParserHandler implements Interceptor {
public class TenantPaginationInterceptor {
//
//	/**
//     * COUNT SQL 解析
//     */
//    private ISqlParser sqlParser;
//    /**
//     * 溢出总页数，设置第一页
//     */
//    private boolean overflow = false;
//    /**
//     * 方言类型
//     */
//    private String dialectType;
//    /**
//     * 方言实现类
//     */
//    private String dialectClazz;
//
//	public static final String SCHEMA_START = "/*!mycat:schema = ";
//
//	public static final String SCHEMA_END = "*/";
//
//    private String getMycatSchema(String originalSql) {
//    	return originalSql.indexOf(SCHEMA_START) != -1 ?  originalSql.substring(0, originalSql.indexOf(SCHEMA_END) + 2) : "";
//    }
//
//    /**
//     * 查询SQL拼接Order By
//     *
//     * @param originalSql 需要拼接的SQL
//     * @param page        page对象
//     * @param orderBy     是否需要拼接Order By
//     * @return
//     */
//    public static String concatOrderBy(String originalSql, IPage page, boolean orderBy) {
//        if (orderBy && (ArrayUtils.isNotEmpty(page.ascs())
//            || ArrayUtils.isNotEmpty(page.descs()))) {
//            StringBuilder buildSql = new StringBuilder(originalSql);
//            String ascStr = concatOrderBuilder(page.ascs(), " ASC");
//            String descStr = concatOrderBuilder(page.descs(), " DESC");
//            if (StringUtils.isNotEmpty(ascStr) && StringUtils.isNotEmpty(descStr)) {
//                ascStr += ", ";
//            }
//            if (StringUtils.isNotEmpty(ascStr) || StringUtils.isNotEmpty(descStr)) {
//                buildSql.append(" ORDER BY ").append(ascStr).append(descStr);
//            }
//            return buildSql.toString();
//        }
//        return originalSql;
//    }
//
//    /**
//     * 拼接多个排序方法
//     *
//     * @param columns
//     * @param orderWord
//     */
//    private static String concatOrderBuilder(String[] columns, String orderWord) {
//        if (ArrayUtils.isNotEmpty(columns)) {
//            return Arrays.stream(columns).filter(StringUtils::isNotEmpty)
//                .map(i -> i + orderWord).collect(joining(StringPool.COMMA));
//        }
//        return StringUtils.EMPTY;
//    }
//
//    /**
//     * Physical Page Interceptor for all the queries with parameter {@link RowBounds}
//     */
//    @Override
//    public Object intercept(Invocation invocation) throws Throwable {
//        StatementHandler statementHandler = (StatementHandler) PluginUtils.realTarget(invocation.getTarget());
//        MetaObject metaObject = SystemMetaObject.forObject(statementHandler);
//
//        // SQL 解析
//        this.sqlParser(metaObject);
//
//        // 先判断是不是SELECT操作
//        MappedStatement mappedStatement = (MappedStatement) metaObject.getValue("delegate.mappedStatement");
//        if (!SqlCommandType.SELECT.equals(mappedStatement.getSqlCommandType())) {
//            return invocation.proceed();
//        }
//
//        // 针对定义了rowBounds，做为mapper接口方法的参数
//        BoundSql boundSql = (BoundSql) metaObject.getValue("delegate.boundSql");
//        Object paramObj = boundSql.getParameterObject();
//
//        // 判断参数里是否有page对象
//        IPage page = null;
//        if (paramObj instanceof IPage) {
//            page = (IPage) paramObj;
//        } else if (paramObj instanceof Map) {
//            for (Object arg : ((Map) paramObj).values()) {
//                if (arg instanceof IPage) {
//                    page = (IPage) arg;
//                    break;
//                }
//            }
//        }
//
//        /**
//         * 不需要分页的场合，如果 size 小于 0 返回结果集
//         */
////        String originalSql = this.rewriteSql(boundSql.getSql());
//        String originalSql = boundSql.getSql();
//
//        String mycatSchema = getMycatSchema(originalSql);
//        if (null == page || page.getSize() < 0) {
//            metaObject.setValue("delegate.boundSql.sql", originalSql);
//            return invocation.proceed();
//        }
//
//        Connection connection = (Connection) invocation.getArgs()[0];
//        DbType dbType = StringUtils.isNotEmpty(dialectType) ? DbType.getDbType(dialectType)
//            : JdbcUtils.getDbType(connection.getMetaData().getURL());
//
//        boolean orderBy = true;
//        if (page.getTotal() == 0) {
//            SqlInfo sqlInfo = SqlParserUtils.getOptimizeCountSql(page.optimizeCountSql(), sqlParser, originalSql);
//            orderBy = sqlInfo.isOrderBy();
//            this.queryTotal(overflow, sqlInfo.getSql(), mappedStatement, boundSql, page, connection, mycatSchema);
//            if (page.getTotal() <= 0) {
//                return invocation.proceed();
//            }
//        }
//        String buildSql = concatOrderBy(originalSql, page, orderBy);
//        originalSql = DialectFactory.buildPaginationSql(page, buildSql, dbType, dialectClazz);
//
//        /*
//         * <p> 禁用内存分页 </p>
//         * <p> 内存分页会查询所有结果出来处理（这个很吓人的），如果结果变化频繁这个数据还会不准。</p>
//         */
//        metaObject.setValue("delegate.boundSql.sql", originalSql);
//        metaObject.setValue("delegate.rowBounds.offset", RowBounds.NO_ROW_OFFSET);
//        metaObject.setValue("delegate.rowBounds.limit", RowBounds.NO_ROW_LIMIT);
//        return invocation.proceed();
//    }
//
//    /**
//     * 查询总记录条数
//     *
//     * @param sql
//     * @param mappedStatement
//     * @param boundSql
//     * @param page
//     */
//    protected void queryTotal(boolean overflowCurrent, String sql, MappedStatement mappedStatement, BoundSql boundSql, IPage page, Connection connection, String mycatSchema) {
//        sql =  mycatSchema + (sql.indexOf(mycatSchema) != -1 ? sql.replace(mycatSchema, "") : sql);
//        try (PreparedStatement statement = connection.prepareStatement(sql)) {
//            DefaultParameterHandler parameterHandler = new MybatisDefaultParameterHandler(mappedStatement, boundSql.getParameterObject(), boundSql);
//            parameterHandler.setParameters(statement);
//            long total = 0;
//            try (ResultSet resultSet = statement.executeQuery()) {
//                if (resultSet.next()) {
//                    total = resultSet.getLong(1);
//                }
//            }
//            page.setTotal(total);
//            /*
//             * 溢出总页数，设置第一页
//             */
//            long pages = page.getPages();
//            if (overflowCurrent && page.getCurrent() > pages) {
//                // 设置为第一条
//                page.setCurrent(1);
//            }
//        } catch (Exception e) {
//            throw ExceptionUtils.mpe("Error: Method queryTotal execution error.", e);
//        }
//    }
//
//    @Override
//    public Object plugin(Object target) {
//        if (target instanceof StatementHandler) {
//            return Plugin.wrap(target, this);
//        }
//        return target;
//    }
//
//    @Override
//    public void setProperties(Properties prop) {
//        String dialectType = prop.getProperty("dialectType");
//        String dialectClazz = prop.getProperty("dialectClazz");
//        if (StringUtils.isNotEmpty(dialectType)) {
//            this.dialectType = dialectType;
//        }
//        if (StringUtils.isNotEmpty(dialectClazz)) {
//            this.dialectClazz = dialectClazz;
//        }
//    }
}